package com.zjp.mg.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.TransactionOptions;
import com.mongodb.WriteConcern;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.TransactionBody;
import com.mongodb.client.result.UpdateResult;
import com.zjp.mg.model.*;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Service
public class OrderSchemeService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private OrderService orderService;
    @Autowired
    private SchemeService schemeService;


    public Order addOrder(OrderSchemeDto dto) {
        Order order = dto.getOrder();
        orderService.insertByAutoId(order);
        List<Scheme> schemeList =
                dto.getSchemeList();
        if (CollUtil.isNotEmpty(schemeList)) {
            schemeList.forEach(bean -> {
                bean.setOrderId(order.getOrderId());
                schemeService.insertByAutoId(bean);
            });
        }

        return order;
    }

    public OrderSchemeVo getOrder(Long orderId) {
        Order order = orderService.findById(orderId);
        List<Scheme> schemeList = schemeService.findByOrderId(orderId);
        return new OrderSchemeVo(order, schemeList);
    }

    public void deleteOrder(Long orderId) {
        logger.info("==removeOrder==orderId=={}", orderId);
        Criteria criteriaOrder = Criteria.where("_id").is(orderId);
        Criteria criteria = Criteria.where("orderId").is(orderId);
        long removeOrder = orderService.remove(new Query(criteriaOrder));
        long removeScheme = schemeService.remove(new Query(criteria));
        logger.info("==removeOrder==count=={}", removeOrder);
        logger.info("==removeScheme==count=={}", removeScheme);
    }

    public UpdateResult updateOrder(OrderSchemeDto dto) {

        Criteria criteriaOrder = Criteria.where("_id").is(dto.getOrder().getOrderId());

        Update update = new Update();
        update.set("orderPrice", new BigDecimal("50"));

        return orderService.updateFirst(Query.query(criteriaOrder), update);
    }

    public Page<Order> pageList(Integer page, Integer pageSize) {
        Query query = new Query();
        PageRequest of = PageRequest.of(page - 1, pageSize);
        return orderService.page(query, of);
    }

    public void group() {
        //$group
        GroupOperation groupOperation =
                Aggregation.group("orderId").sum("schemeType").as("totalPop");
        //$match
        MatchOperation matchOperation = Aggregation.match(Criteria.where("totalPop").gte(5));
        // 按顺序组合每一个聚合步骤
        TypedAggregation<Scheme> typedAggregation =
                Aggregation.newAggregation(Scheme.class,
                        groupOperation, matchOperation);
        //执行聚合操作,如果不使用 Map，也可以使用自定义的实体类来接收数据
        AggregationResults<Map> aggregationResults =
                schemeService.
                        getMongoTemplate().aggregate(typedAggregation, Map.class);
        // 取出最终结果
        List<Map> mappedResults = aggregationResults.getMappedResults();
        for (Map map : mappedResults) {
            System.out.println(map);
        }
    }

    @Autowired
    MongoClient mongoClient;

    public void transaction(Apple apple) {

        ClientSession clientSession = mongoClient.startSession();

        TransactionOptions txnOptions = TransactionOptions.builder()
                .readPreference(ReadPreference.primary())
                .readConcern(ReadConcern.LOCAL)
                .writeConcern(WriteConcern.MAJORITY)
                .build();
        TransactionBody<String> txnBody = () -> {
            MongoCollection<Document> coll1 = mongoClient.getDatabase("data_mg").getCollection("apple");
            MongoCollection<Document> coll2 = mongoClient.getDatabase("data_mg").getCollection("apple");
            coll1.insertOne(clientSession, new Document(BeanUtil.beanToMap(apple)));
            coll2.insertOne(clientSession, new Document(BeanUtil.beanToMap(apple)));
            return "Inserted into collections in different databases";
        };
        try {
            clientSession.withTransaction(txnBody, txnOptions);
        } catch (RuntimeException e) {
            // some error handling
        } finally {
            clientSession.close();
        }
    }

    @Autowired
    MongoTemplate mongoTemplate;

    @Transactional(rollbackFor = Exception.class)
    public void transactionV2(Apple apple) {

        mongoTemplate.save(apple);


        Assert.isTrue(false, "XXXX");

        mongoTemplate.save(apple);

    }


}
